#include <mfile.hpp>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include "stdafx.h"
#include "comm.h"

mFile::~mFile(){
	if( f_ins.is_open() ){
		f_ins.close();
	}
}

bool 
mFile::create_dir( const char * dirname_s ){
/*	#define MKDIR_CMD "mkdir -p %s"
	#define CMD_LEN (PATH_MAX +sizeof(MKDIR_CMD))
	char cmd[ CMD_LEN ];
	memset( cmd , 0 , CMD_LEN);
	sprintf( cmd , MKDIR_CMD ,dirname_s );

	if( -1 == system( cmd )){
		SAY( DP_DEBUG ,"Create directory failed!\n");
		return false;
	}

	return true;
*/
	if( NULL == dirname_s ){
		SAY( DP_DEBUG , "dirname_s is NULL\n");
		return false;
	}
		
/*	if( 1 == strlen( dirname_s) || dirname_s[0] == '.' || dirname_s[0] == '/' ){
		SAY( DP_DEBUG , )
		return false;
	}
*/
	int retval = mkdir( dirname_s  , 0777 );
	if( -1 == retval ){
		if( ENOENT == errno ){
			char * new_dirname_s = strdup( dirname_s );

			bool retbool = create_dir( dirname(new_dirname_s) );

			free( new_dirname_s );
			
			if( retbool ){
				retval = mkdir( dirname_s , 0777 );
				if( -1 == retval ){
					SAY( DP_DEBUG ,"make subdir error \n");
					return false;
				}
			}else{
				SAY( DP_DEBUG ,"make parent dir error \n");
				return false;
			}
		}else{
			SAY( DP_DEBUG , "Some error occured when calling mkdir(2)\n");
			return false;
		}
	}
	return true;
		
}
bool
mFile::create( const char * filename_s ){

	struct stat status;
	if( NULL == filename_s ){
		SAY( DP_DEBUG ,"Ptr is NULL\n");
		ret_err MF_ERR_COM_NULLPTR;
	}

	path_name = filename_s;
	
	int ret_val = ::stat( filename_s , &status );
	if( -1 == ret_val ){
		switch(errno){
		case ENOENT: //need to be created
			SAY( DP_DEBUG ,"Create a new file\n");
			f_ins.open( filename_s , ios::out );
			if( !f_ins.is_open() ){	//need to create directory
				char path[PATH_MAX];
				strncpy(path , filename_s , PATH_MAX );
				if( ! create_dir( dirname(path) ) ){
					SAY( DP_DEBUG , "create_dir failed\n");
					return false;
				}

				f_ins.open( filename_s , ios::out );
				if( !f_ins.is_open() ){	//need to create directory
				
					SAY( DP_DEBUG ,"An Error Occured while creating a file\n");
					return false;
				}
			}
			f_ins.close();
			break;
		default: //other errors 
			SAY( DP_DEBUG ,"When we try to handle the file \"%s\" ,we got the error whose errno is %d\n" , errno);
			return false;
		}
	}
	
	return true;	
}

int 
mFile::open( const char * filename_s ){

	if( !create( filename_s ) ){
		SAY( DP_DEBUG , "create failed\n" );
		ret_err MF_ERR_OP_CREATE ;
	}

	f_ins.clear();//clear the iostate;

	f_ins.open( filename_s , ios::out|ios::in|ios::binary );
	if( !f_ins.is_open() ){
		SAY( DP_DEBUG ,"open failed\n");
		ret_err MF_ERR_OP_OPEN;
	}
	
	rd_pos = f_ins.tellp();
	wt_pos = f_ins.tellg();
}

bool 
mFile::is_open(){
	return f_ins.is_open();
}

void 
mFile::close(){
	f_ins.close();
}

int 
mFile::read( char * buffer_p  ,int buf_size , int type ){

	if( NULL == buffer_p || 0== buf_size ){
		SAY( DP_DEBUG , "Ptr is NULL or buffer size is equal to zero\n");
		ret_err MF_ERR_COM_NULLPTR;
	} 
	
	if( !is_open() ){
		SAY( DP_DEBUG ,"There isn't an opend file right now\n");
		ret_err MF_ERR_COM_NOTOPEN;
	}
	
	switch( type ){
	case MF_OPT_RD_BEG:
		f_ins.seekg(0 , ios::beg);
		break;
	case MF_OPT_RD_CUR:
		f_ins.seekg( rd_pos );
	}

	f_ins.read( buffer_p , buf_size );
	ios_base::iostate st = f_ins.rdstate();
	if( f_ins.fail() ){
		if( !(f_ins.rdstate() & ifstream::eofbit) ){
			SAY( DP_DEBUG , "read failed\n");
			ret_err MF_ERR_RD_FAILED;
		}
		f_ins.clear();
	}

	rd_pos = f_ins.tellg();

	return f_ins.gcount();
}

int 
mFile::write( const char * content_p , int cont_len , int type ){

	if( NULL == content_p || 0== cont_len ){
		SAY( DP_DEBUG , "Ptr is NULL or buffer size is equal to zero\n");
		ret_err MF_ERR_COM_NULLPTR;
	} 
	
	if( !is_open() ){
		SAY( DP_DEBUG ,"There isn't an opend file right now\n");
		ret_err MF_ERR_COM_NOTOPEN;
	}

	switch( type ){
	case MF_OPT_WT_BEG:
		f_ins.seekp(0 , ios::beg);
		break;
	case MF_OPT_WT_CUR:
		f_ins.seekp( wt_pos );
	}

	f_ins.write( content_p , cont_len );

	if( f_ins.fail() ){
		f_ins.clear();
		SAY( DP_DEBUG ,"Write failed!\n");
		ret_err MF_ERR_WT_FAILED; 
	}
	f_ins.sync();
	wt_pos = f_ins.tellp();
	return cont_len;
}
/*
bool
mFile::stat( struct stat * stat_p ){
	
	if( NULL == stat_p ){
		SAY( DP_DEBUG ,"stat_p is NULL\n");
		ret_err MF_ERR_COM_NULLPTR;
	}

	if( !f_ins.is_open() ){
		SAY( DP_DEBUG , "Not opened\n");
		ret_err MF_ERR_COM_NOTOPEN;
	}

	int fd = f_ins.fd();
	int ret_val = ::fstat( fd , stat_p );

	if( -1 == ret_val ){
		SAY( DP_DEBUG , "fstat failed\n");
		return false;
	}
	return true;
}
*/

bool
mFile::rename( const char * new_name_s ){
	
	if( NULL == new_name_s ){
		SAY( DP_DEBUG ,"new_name_s is NULL\n");
		return false;
	}

	if( path_name.empty() ){
		SAY( DP_DEBUG ,"path_name is NULL\n");
		return false;
	}

	f_ins.close();

	int ret_val = ::rename( path_name.c_str() , new_name_s );
	if( -1 == ret_val ){
		SAY( DP_DEBUG , "rename failed\n");
		return false;
	}
	open( new_name_s );
	path_name = new_name_s;
	return true;
}
	
bool
mFile::remove( ){

	if( path_name.empty() ){
		SAY( DP_DEBUG ,"path_name is NULL\n");
		return false;
	}

	f_ins.close();

	int ret_val = ::remove( path_name.c_str() );
	if( -1 == ret_val ){
		SAY( DP_DEBUG ,"remove failed\n");
		return false; 
	}
	
	path_name = "";

	return true;	
}

